#include <iterator>
#include <unistd.h>
#include "MarkupSTL.h"
#include "global.h"
#include "cmd.h"
#include "Game.h"
#include "RedisClient.h"
#include "Logic.h"
#include "json.h"
#include "globalExtern.h"
#include "Host.h"
#include <string>
#include <algorithm>
#include "log.h"
#include "util.h"
#include "base64.h"
#include "Md5.h"
#include "bsl_string.h"
#include <sstream>
#include <map>
#include <time.h>
#include <cstdlib>
#include <limits>
#include "public_define.h"
#include "cache.h"
#include "minutelisten.h"
#include "AccountHandler.h"
#include "accountmgr.h"
#include "streamdata.h"
#include "1700_account.pb.h"
#include "2000_topic.pb.h"
#include "800_online.pb.h"
#include "1700_login.pb.h"
#include "LogHandler.h"
#include "DbPart.h"
#include "currencymgr.h"


CGameServer::CGameServer()
{
}

CGameServer::~CGameServer()
{
}

int CGameServer::OnBYTimeOut(int Timerid)
{
	switch (Timerid)
	{
	case TIMER_LOGIN_CACHE_CHECK:
		procTimerLoginCacheCheck();
		break;
	
	case TimerID::TIMER_MINITE:
		MinuteListen::Instance()->OnTick();
		break;
	default:
		break;
	}

	return 0;
}

bool CGameServer::InitGame()
{
	log_info("game init");
	char conf_path[128] = "./config.xml";
	if (!ReadCommonConf(conf_path))
	{
		log_boot("InitGame ReadCommonConf failed. path:[%s]", conf_path);
		return false;
	}

	StartTimer(TIMER_LOGIN_CACHE_CHECK, LOGIN_CACHE_EXPIRE, true);
	StartTimer(TIMER_MINITE, TIME_MINUTE_SEC, true);
	return true;
}

bool CGameServer::ReadCommonConf(const char* strxml)
{
	CMarkupSTL  markup;
	if (!markup.Load(strxml))
	{
		log_error("Load xml %s failed", strxml);
		return false;
	}

	if (!markup.FindElem("application"))
	{
		log_error("Not Found Elem [application] in xml[%s]", strxml);
		return false;
	}

	if (!markup.IntoElem())
	{
		log_error("IntoElem [application] failed.");
		return false;
	}

	std::string uname;
	if (!markup.FindElem("default_prefix"))
	{
		log_error("Not Found Elem [default_prefix] in xml[%s]", strxml);
		uname = "Player";
	}
	else
	{
		uname = markup.GetAttrib("uname");
	}
	CDbPart::Instance()->SetDefaultUname(uname);
	
	return true;
}


int CGameServer::ProcessPacket(SocketHandler * pHandler, NETInputPacket* inputPkg)
{
	do
	{
		unsigned int cmd = inputPkg->GetCmdType();
		log_debug("cmd=0x%x,  svid=%u, ", inputPkg->GetCmdType(), pHandler->getId());
		
		if (0 == LogHandler::Instance()->ProcessPacket(m_pHost, pHandler, inputPkg))
		{
			return 0;
		}

		switch (cmd)
		{
			case account_proto::ACCOUNT_CMD_GET_ACCOUNT_REQ:
				ProcGetAccount(pHandler, inputPkg);
				break;
			case account_proto::ACCOUNT_CMD_GET_ACCOUNT_BY_UUID_REQ:
				ProcGetAccountByUuid(pHandler, inputPkg);
				break;
			case account_proto::ACCOUNT_CMD_GET_ACCOUNT_BY_UID_REQ:
				ProcGetAccountByUid(pHandler, inputPkg);
				break;
			case account_proto::ACCOUNT_CMD_GEN_LOGIN_TOKEN_REQ:
				ProcGenLoginToken(pHandler, inputPkg);
				break;
			case account_proto::ACCOUNT_CMD_VERIFY_LOGIN_TOKEN_REQ:
				ProcVerifyLoginToken(pHandler, inputPkg);
				break;
			case account_proto::ACCOUNT_CMD_UPDATE_ACCOUNT_TOKEN_REQ:
				ProcUpdateAccountToken(pHandler, inputPkg);
				break;
			case online::ONLINE_CMD_ONLINE_GAME_STATE_RESP:
				ProcInGameQueryRsp(pHandler, inputPkg);
				break;
			default:
				log_error("cmd=0x%x,  svid=%d, err no proc", cmd, pHandler->getId());
				break;
		}
		return 1;
	}while(0);
	return -1;
}

void CGameServer::ProcGetAccount(SocketHandler* pHandler, NETInputPacket* inputPkg)
{
	account_proto::GetAccountReq req;
	account_proto::GetAccountResp resp;
	do
	{
		if (!inputPkg->parsePb(&req))
		{
			log_error("parse pb account_proto::GetAccountReq failed");
			resp.set_err_code(1);
			break;
		}
		if (0 == req.uid())
		{
			log_error("param error,%s", req.ShortDebugString().c_str());
			resp.set_err_code(2);
			break;
		}

		resp.set_uid(req.uid());

		std::string uuid, agency, username, token, hall_url, platform, currency, ext;
		std::uint32_t agency_id;
		std::int64_t balance;
		bool ret = Cache::Instance()->InfoGet(req.uid(), uuid, agency, username, agency_id, token, hall_url, platform, balance, currency, ext);
		if (!ret || uuid.empty())
		{
			log_error("get info err,uid,%u, ret,%d,uuid,%s", req.uid(), (ret ? 1 : 0), uuid.c_str());
			resp.set_err_code(3);
			break;
		}
		stCurrency* st_currency = CurrencyMgr::Instance()->Get(currency);
		if (st_currency == nullptr)
		{
			log_error("get currency info err,uid,%u, ret,%d,uuid,%s, currency:%s", req.uid(), (ret ? 1 : 0), uuid.c_str(), currency.c_str());
			resp.set_err_code(4);
			break;
		}

		resp.set_err_code(0);
		resp.set_agency(agency);
		resp.set_username(username);
		resp.set_uuid(uuid);
		resp.set_agency_id(agency_id);
		resp.set_token(token);
		resp.set_hall_url(hall_url);
		resp.set_platform(platform);
		resp.set_currency(currency);
		resp.set_currency_unit_multi(st_currency->unit_multi);
		resp.set_currency_label(st_currency->label);
		resp.set_gameinfo(ext);
	} while (false);
	if (!req.trans().empty())
		resp.set_trans(req.trans());
	m_pHost->SendPb(pHandler, account_proto::ACCOUNT_CMD_GET_ACCOUNT_RESP, &resp);
}

void CGameServer::ProcGetAccountByUuid(SocketHandler* pHandler, NETInputPacket* inputPkg)
{
	account_proto::GetAccountByUuidReq req;
	account_proto::GetAccountByUuidResp resp;
	do
	{
		if (!inputPkg->parsePb(&req))
		{
			log_error("parse pb account_proto::GetAccountReq failed");
			resp.set_err_code(1);
			break;
		}

		std::string uuid = AccountMgr::Instance()->Uuid(req.agency(), req.username());
		std::uint32_t uid = 0;
		std::uint32_t agency_id;
		std::string agency, username;
		if (!AccountMgr::Instance()->GetUserByUuid(uuid, uid, agency, username, agency_id))
		{
			log_error("uuid:%s not found", uuid.c_str());
			resp.set_err_code(2);
			break;
		}

		if (uid == 0)
		{
			log_error("uuid:%s, uid invalid", uuid.c_str());
			resp.set_err_code(3);
			break;
		}
		resp.set_err_code(0);
		resp.mutable_acc()->set_uid(uid);
		resp.mutable_acc()->set_agency(agency);
		resp.mutable_acc()->set_username(username);
		resp.mutable_acc()->set_uuid(uuid);
		resp.mutable_acc()->set_agency_id(agency_id);

	} while (false);
	if (!req.trans().empty())
		resp.set_trans(req.trans());
	m_pHost->SendPb(pHandler, account_proto::ACCOUNT_CMD_GET_ACCOUNT_BY_UUID_RESP, &resp);
}

void CGameServer::ProcGetAccountByUid(SocketHandler* pHandler, NETInputPacket* inputPkg)
{
	account_proto::GetAccountByUidReq req;
	account_proto::GetAccountByUidResp resp;
	do
	{
		if (!inputPkg->parsePb(&req))
		{
			log_error("parse pb account_proto::GetAccountReq failed");
			resp.set_err_code(1);
			break;
		}

		std::uint32_t uid = req.uid();
		std::string uuid = "";
		std::uint32_t agency_id;
		std::string agency, username;
		if (!AccountMgr::Instance()->GetUserByUid(uid, uuid, agency, username, agency_id))
		{
			log_error("uuid:%s not found", uuid.c_str());
			resp.set_err_code(2);
			break;
		}
		if (uid == 0)
		{
			log_error("uuid:%s, uid invalid", uuid.c_str());
			resp.set_err_code(3);
			break;
		}
		resp.set_err_code(0);
		resp.mutable_acc()->set_uid(uid);
		resp.mutable_acc()->set_agency(agency);
		resp.mutable_acc()->set_username(username);
		resp.mutable_acc()->set_uuid(uuid);
		resp.mutable_acc()->set_agency_id(agency_id);

	} while (false);
	if (!req.trans().empty())
		resp.set_trans(req.trans());
	m_pHost->SendPb(pHandler, account_proto::ACCOUNT_CMD_GET_ACCOUNT_BY_UID_RESP, &resp);
}

void CGameServer::ProcUpdateAccountToken(SocketHandler* pHandler, NETInputPacket* inputPkg)
{
	account_proto::UpdateAccountTokenReq req;
	account_proto::UpdateAccountTokenResp resp;
	do
	{
		// 禁止客户端直接修改token
		if (SERVER_TYPE_AGENT == pHandler->getType())
		{
			log_error("visitor must not be player use client");
			resp.set_err_code(6);
			break;
		}

		if (!inputPkg->parsePb(&req))
		{
			log_error("parse pb account_proto::UpdateAccountReq failed");
			resp.set_err_code(1);
			break;
		}
		if (req.uid() == 0)
		{
			log_error("uid is 0, msg:%s", req.ShortDebugString().c_str());
			resp.set_err_code(2);
			break;
		}

		resp.set_uid(req.uid());

		std::string uuid, agency, username, token, hall_url, platform, currency, ext;
		std::uint32_t agency_id;
		std::int64_t balance;
		bool ret = Cache::Instance()->InfoGet(req.uid(), uuid, agency, username, agency_id, token, hall_url, platform, balance, currency, ext);
		if (!ret || uuid.empty())
		{
			log_error("get info err,uid,%u, ret,%d,uuid,%s", req.uid(), (ret?1:0), uuid.c_str());
			resp.set_err_code(3);
			break;
		}
		bool ret1 = Cache::Instance()->TokenUpdate(req.uid(), req.token());
		if (!ret1)
		{
			log_error("update token fail,uid,%u,token,%s", req.uid(), req.token().c_str());
			resp.set_err_code(4);
			break;
		}
		stCurrency* st_currency = CurrencyMgr::Instance()->Get(currency);
		if (st_currency == nullptr)
		{
			log_error("get currency info fail,uid:%u,token:%s,currency:%s", req.uid(), req.token().c_str(), currency.c_str());
			resp.set_err_code(5);
			break;
		}

		resp.set_err_code(0);
		resp.set_agency(agency);
		resp.set_username(username);
		resp.set_uuid(uuid);
		resp.set_agency_id(agency_id);
		resp.set_token(token);
		resp.set_hall_url(hall_url);
		resp.set_platform(platform);
		resp.set_currency(currency);
		resp.set_currency_unit_multi(st_currency->unit_multi);
		resp.set_currency_label(st_currency->label);
		resp.set_gameinfo(ext);
	} while (false);

	if (!req.trans().empty())
		resp.set_trans(req.trans());
	m_pHost->SendPb(pHandler, account_proto::ACCOUNT_CMD_UPDATE_ACCOUNT_TOKEN_RESP, &resp);
}

static bool EcodeToken(const std::string& agency, const std::string& user_name, const std::string& uuid, const std::uint32_t uid, const std::string& token, const std::int64_t balance, 
	const std::uint32_t game, const std::string& platform, const std::string& gameinfo, const std::uint64_t expi, std::string& gentoken)
{
	//srand((unsigned)time(NULL));
	std::stringstream oss;
	oss << "uuid=" << uuid
	<< "&uid=" << uid
	<< "&token=" << token
	<< "&balance=" << balance
	<< "&game=" << game
	<< "&gameinfo=" << gameinfo
	<< "&expi=" << expi;
	std::string sign = oss.str() + "&" + TS_LOGIN_TOKEN;
	oss << "&sign=" << MD5(sign).toStr();

	char codeDst[1024] = {0};
	log_info("EcodeToken = %s", oss.str().c_str());
	Base64encode(codeDst, oss.str().c_str(), oss.str().length());
	gentoken = codeDst;

	return true;
}

static bool MakeSign(const std::string& uuid, const std::uint32_t uid, const std::string& token, const std::int64_t balance, 
	const std::uint32_t game, const std::string& gameinfo, const std::uint64_t expi, std::string& gensign)
{
	//srand((unsigned)time(NULL));
	std::stringstream oss;
	oss << "uuid=" << uuid
		<< "&uid=" << uid
		<< "&token=" << token
		<< "&balance=" << balance
		<< "&game=" << game
		<< "&gameinfo=" << gameinfo
		<< "&expi=" << expi;
	std::string sign = oss.str() + "&" + TS_LOGIN_TOKEN;
	gensign = MD5(sign).toStr();

	return true;
}

static int DcodeToken(const std::string& token, TokenInfo& tokenInfo)
{
	char decodeBuf[2048] = {0};
	Base64decode(decodeBuf, token.c_str());
	if (::strstr(decodeBuf, "sign") == NULL)
	{
		log_error("DcodeToken failed!! sign is null,token:%s", token.c_str());
		return 1;
	}
	if (::strstr(decodeBuf, "uid") == NULL)
	{
		log_error("DcodeToken failed!! uid is null,token:%s", token.c_str());
		return 1;
	}
	// 解析token
	std::map<std::string, std::string> params = CTools::ParseUrlParams(decodeBuf);
	if ( params.end() == params.find("uuid") || params.end() == params.find("uid"))
	{
		log_error("DcodeToken failed!! find no uuid or uid,token:%s", token.c_str());
		return 1;
	}
	tokenInfo.uuid = params["uuid"];
	tokenInfo.uid = ::strtoul(params["uid"].c_str(), NULL, 10);
	tokenInfo.token = params["token"];
	tokenInfo.balance = ::atoll(params["balance"].c_str());
	tokenInfo.game = ::strtoul(params["game"].c_str(), NULL, 10);
	tokenInfo.gameinfo = params["gameinfo"];
	tokenInfo.expi = ::strtoull(params["expi"].c_str(), NULL, 10);
	tokenInfo.sign = params["sign"];

	std::string sign;
	//std::string gentoken;
	if (!MakeSign(tokenInfo.uuid, tokenInfo.uid, tokenInfo.token, tokenInfo.balance, tokenInfo.game, tokenInfo.gameinfo, tokenInfo.expi, sign))
	{
		log_error("EcodeToken failed!! token:%s", token.c_str());
		return 1;
	}

	if (tokenInfo.sign.compare(sign) != 0)
	{
		log_error("sign not match, sign_md5:%s, msg:%s", tokenInfo.sign.c_str(), token.c_str());
		return 1;
	}
	// 验证时间
	std::uint64_t now = time(NULL);
	if (now > tokenInfo.expi)
	{
		log_error("token expired, now:%llu, msg:%s", now, token.c_str());
		return 2;
	}
	log_info("DCODE_TOKEN SUCCESS");

	return 0;
}

void CGameServer::ProcGenLoginToken(SocketHandler* pHandler, NETInputPacket* inputPkg)
{
	account_proto::GenLoginTokenReq req;
	account_proto::GenLoginTokenResp resp;
	do
	{
		// 增加校验 只能 access服务调用
		if (pHandler->getType() != SERVER_TYPE_ACCESS_PLAT)
		{
			log_error("visitor must be access service");
			resp.set_err_code(6);
			break;
		}

		if (!inputPkg->parsePb(&req))
		{
			log_error("parse pb account_proto::GetTokenReq failed");
			resp.set_err_code(1);
			break;
		}
		log_info("req:%s", req.ShortDebugString().c_str());

		if (req.agency().empty() || req.username().empty()|| req.token().empty())
		{
			log_error("param error,%s", req.ShortDebugString().c_str());
			resp.set_err_code(2);
			break;
		}

		std::string uuid = req.agency() + ":" + req.username();
		std::uint32_t uid = 0;
		bool ret = AccountMgr::Instance()->Uid(uuid, uid);
		if (!ret)
		{
			resp.set_err_code(3);
			break;
		}
		if (uid == 0)  // 新账号逻辑
		{
			// 生成uid
			uid = CAccountHandler::Instance()->GetNewUidFromRedis();
			if (0 == uid)
			{
				log_error("dispatch uid failed,%s", req.ShortDebugString().c_str());
				resp.set_err_code(4);
				break;
			}

			resp.set_uid(uid);
			// 设置 数据
			if (!AccountMgr::Instance()->Reg(uuid, uid, req.agency(), req.username(), req.agency_id(), req.token(), req.hall_url(), req.platform(), req.balance(), req.currency(), req.gameinfo()))
			{
				log_error("reg failed,%s", req.ShortDebugString().c_str());
				resp.set_err_code(3);
				break;
			}
			log_debug("Regnewplayer uid = %u", uid);
			// 发创建玩家数据信息给flow服
			account_proto::AccountInfo account;
			account.set_uid(uid);
			account.set_agency(req.agency());
			account.set_agency_id(req.agency_id());
			account.set_username(req.username());
			m_pHost->SendtoSrv(account_proto::ACCOUNT_CMD_REGISTER_NEW_PLAYER_PUSH, SERVER_TYPE_FLOW, &account, uid);
		}
		else  // 已有账号,更新信息
		{
			resp.set_uid(uid);
			// 更新 数据
			if (!AccountMgr::Instance()->Update(uuid, uid, req.agency(), req.username(), req.agency_id(), req.token(), req.hall_url(), req.platform(), req.balance(), req.currency(), req.gameinfo()))
			{
				log_error("update failed,%s", req.ShortDebugString().c_str());
				resp.set_err_code(3);
				break;
			}
		}

		std::string	gentoken;
		std::uint64_t expi = std::time(NULL) + TS_USER_TOKEN_EXPIRE;
		if (!EcodeToken(req.agency(), req.username(), uuid, uid, req.token(), req.balance(), req.game(), req.platform(), req.gameinfo(), expi, gentoken))
		{
			log_error("EcodeToken failed,%s", req.ShortDebugString().c_str());
			resp.set_err_code(5);
			break;
		}
		resp.set_err_code(0);
		resp.set_token(gentoken);

	} while (false);

	if (!req.trans().empty())
	{
		resp.set_trans(req.trans());
	}
	m_pHost->SendPb(pHandler, account_proto::ACCOUNT_CMD_GEN_LOGIN_TOKEN_RESP, &resp);
}

void CGameServer::ProcVerifyLoginToken(SocketHandler* pHandler, NETInputPacket* inputPkg)
{
	int bSta = 0;
	std::uint32_t uid = 0;
	account_proto::VerifyLoginTokenReq stReq;
	account_proto::VerifyLoginTokenResp rsp;
	bool forbit_online_check = false;
	if (pHandler->getType() == SERVER_TYPE_GAME_API)
	{
		forbit_online_check = true;
	}

	do
	{
		std::uint32_t temp_uin = inputPkg->GetSrcSvid();
		rsp.set_temp_uin(temp_uin);
		bool bRet = inputPkg->parsePb(&stReq);
		if (!bRet)
		{
			log_error("parsePb is failed");
			bSta = 1;
			break;
		}

		if (stReq.token().empty())
		{
			log_error("szToken is empty");
			bSta = 2;
			break;
		}

		// 解析token
		TokenInfo tokenInfo;
		int ret = DcodeToken(stReq.token(), tokenInfo);
		if (0 != ret)
		{
			log_error("DcodeToken failed!!,token:%s", stReq.token().c_str());
			bSta = 3;
			if (2 == ret)
			{
				bSta = 4;
			}
			break;
		}

		uid = tokenInfo.uid;

		std::uint32_t uid1 = 0;
		bool ret1 = AccountMgr::Instance()->Uid(tokenInfo.uuid, uid1);
		if (!ret1)
		{
			bSta = 5;
			break;
		}
		if (0 == uid1 || uid !=  uid1)
		{
			bSta = 6;
			break;
		}

		rsp.set_uid(uid);
		std::string uuid;

		stCacheLoginInfo cacheAccount;
		bool ret2 = Cache::Instance()->InfoGet(uid, uuid, cacheAccount.agency, cacheAccount.username, cacheAccount.agencyId, cacheAccount.token, cacheAccount.hallUrl, cacheAccount.platform, cacheAccount.balance, cacheAccount.currency, cacheAccount.ext);
		if (ret2)
		{
			if (uuid != tokenInfo.uuid || cacheAccount.token != tokenInfo.token)
			{
				log_error("wrong tokeninfo,tokeninfo,uuid,%s,token,%s,cache,uuid,%s,token,%s",tokenInfo.uuid.c_str(), tokenInfo.token.c_str(), uuid.c_str(), cacheAccount.token.c_str());
				bSta = 7;
				break;
			}
			if (cacheAccount.balance != tokenInfo.balance)
			{
				log_error("wrong tokeninfo,balence,%lld,cache,balence,%lld", tokenInfo.balance, cacheAccount.balance);
			}
		}
		else 
		{
			log_error("get info fail,%u", uid);
		}
		
		stCurrency* st_currency = CurrencyMgr::Instance()->Get(cacheAccount.currency);
		if (st_currency == nullptr)
		{
			log_error("get currency info fail,uid:%u,token:%s,currency:%s", uid, cacheAccount.token.c_str(), cacheAccount.currency.c_str());
			bSta = 8;
			break;
		}

		// 不查询online状态
		if (forbit_online_check)
		{
			rsp.set_agency(cacheAccount.agency);
			rsp.set_agency_id(cacheAccount.agencyId);
			rsp.set_username(cacheAccount.username);
			rsp.set_token(cacheAccount.token);
			rsp.set_balance(cacheAccount.balance);
			rsp.set_game(tokenInfo.game);
			rsp.set_hall_url(cacheAccount.hallUrl);
			rsp.set_platform(cacheAccount.platform);
			rsp.set_gameinfo(cacheAccount.ext);
			rsp.set_currency(cacheAccount.currency);
			rsp.set_currency_unit_multi(st_currency->unit_multi);
			rsp.set_currency_label(st_currency->label);
			rsp.set_result(0);
			if (!stReq.trans().empty()) rsp.set_trans(std::move(stReq.trans()));
			
			// 直接回包
			log_debug("proc,uid:%u,stype:%u,svid:%u,result:%d", rsp.uid(), pHandler->getType(), pHandler->getId(),rsp.result());
			m_pHost->SendPb(pHandler, account_proto::ACCOUNT_CMD_VERIFY_LOGIN_TOKEN_RESP, &rsp);
			return;
		}

		cacheAccount.currency_unit_multi = st_currency->unit_multi;
		cacheAccount.currency_label = st_currency->label;

		cacheAccount.agentSrvId = pHandler->getId();
		cacheAccount.uid = uid;
		cacheAccount.tempUin = temp_uin;
		cacheAccount.game = tokenInfo.game;
		cacheAccount.procTime = ::time(NULL);
		if (!stReq.trans().empty())
		{
			cacheAccount.trans.assign(stReq.trans().data(), stReq.trans().size());
		}

		std::uint32_t seq = genSeq();

		NETOutputPacket pkg;
		pkg.Begin(0);
		pkg.WriteInt(seq);
		pkg.WriteInt64(cacheAccount.procTime);
		pkg.End();

		m_cacheQueue.emplace(cacheAccount.procTime, seq);
		m_cacheAccountInfo.emplace(seq, std::move(cacheAccount));

		online::OnlineGameStateReq req;
		req.set_uid(uid);
		req.set_trans(pkg.packet_buf(), pkg.packet_size());
		m_pHost->SendtoSrv(online::ONLINE_CMD_ONLINE_GAME_STATE_REQ, SERVER_TYPE_ONLINE, &req, uid);

		return;
	}while(0);

	rsp.set_result(bSta);
	if (!stReq.trans().empty())
	{
		rsp.set_trans(stReq.trans());
	}

	log_debug("resp:%s", rsp.ShortDebugString().c_str());
	m_pHost->SendPlayerPb(pHandler, account_proto::ACCOUNT_CMD_VERIFY_LOGIN_TOKEN_RESP, uid, &rsp);

	return;
}

void CGameServer::ProcInGameQueryRsp(SocketHandler* pHandler, NETInputPacket* inputPkg)
{
	online::OnlineGameStateResp msg;
	if (!inputPkg->parsePb(&msg))
	{
		log_error("parse pb fail");
		return;
	}
	if (0 == msg.uid() || 0 != msg.result())
	{
		log_error("wrong data,uid,%u,result,%d", msg.uid(), msg.result());
	}
	if (msg.trans().empty())
	{
		log_error("in game req trans empty,uid,%u", msg.uid());
		return;
	}

	NETInputPacket pack;
	if (!pack.Copy(msg.trans().data(), msg.trans().size()))
	{
		log_error("parse pack fail");
		return;
	}

	std::uint32_t seq = pack.ReadInt();
	
	std::map<std::uint32_t, stCacheLoginInfo>::const_iterator itor = m_cacheAccountInfo.find(seq);
	if (m_cacheAccountInfo.end() == itor)
	{
		log_info("find no cache,uid,%u,seq,%u,proctime,%llu,now,%llu", msg.uid(), seq, pack.ReadInt64(), ::time(NULL));
		return;
	}

	if (0 == itor->second.agentSrvId)
	{
		log_error("unexcept agent srv id");
	}
	if (msg.uid() != itor->second.uid)
	{
		log_error("uid not match,%u,%u", msg.uid(), itor->second.uid);
	}

	account_proto::VerifyLoginTokenResp rsp;
	rsp.set_result(0);
	rsp.set_temp_uin(itor->second.tempUin);
	rsp.set_uid(itor->second.uid);
	rsp.set_agency(itor->second.agency);
	rsp.set_agency_id(itor->second.agencyId);
	rsp.set_username(itor->second.username);
	rsp.set_token(itor->second.token);
	rsp.set_balance(itor->second.balance);
	rsp.set_game(itor->second.game);
	rsp.set_hall_url(itor->second.hallUrl);
	rsp.set_platform(itor->second.platform);
	rsp.set_gameinfo(itor->second.ext);
	rsp.set_currency(itor->second.currency);
	rsp.set_currency_unit_multi(itor->second.currency_unit_multi);
	rsp.set_currency_label(itor->second.currency_label);
	if (!itor->second.trans.empty())
	{
		rsp.set_trans(itor->second.trans);
	}
	if (msg.gamesrvid() > 0)
	{
		account_proto::InGameInfo* ingameinfo = rsp.mutable_ingame_info();
		ingameinfo->set_game_id(msg.gameid());
		ingameinfo->set_game_srvtype(msg.gamesrvtype());
		ingameinfo->set_game_svid(msg.gamesrvid());
		ingameinfo->set_game_tid(msg.tableid());
	}

	if (itor->second.agentSrvId > 0)
	{
		log_debug("resp:%s", rsp.ShortDebugString().c_str());
		m_pHost->SendToPlayerViaAgent(account_proto::ACCOUNT_CMD_VERIFY_LOGIN_TOKEN_RESP, &rsp, itor->second.uid, itor->second.agentSrvId);
	}
	log_debug("proc,uid,%u,seq,%u,agentsrv id,%u,proctime,%llu,now,%llu", msg.uid(), seq, itor->second.agentSrvId, itor->second.procTime, ::time(NULL));

	std::pair <std::multimap<std::uint64_t, std::uint32_t>::const_iterator, std::multimap<std::uint64_t, std::uint32_t>::const_iterator> ret = m_cacheQueue.equal_range(itor->second.procTime);
	for (std::multimap<std::uint64_t, std::uint32_t>::const_iterator itor1 = ret.first; itor1 != ret.second; ++itor1)
	{
		if (seq == itor1->second)
		{
			m_cacheQueue.erase(itor1);
			log_debug("cache queue erase,%u", itor1->second);
			break;
		}
	}
	m_cacheAccountInfo.erase(itor);

	return;
}

int CGameServer::procTimerLoginCacheCheck(void)
{
	std::uint64_t now = ::time(NULL);
	for (std::multimap<std::uint64_t, std::uint32_t>::const_iterator itor = m_cacheQueue.begin(); m_cacheQueue.end() != itor; )
	{
		if (itor->first + 2 <= now)
		{
			procTimeoutCache(itor->second, itor->first);
			m_cacheQueue.erase(itor++);
		}
		else
		{
			break;
		}
	}

	return 0;
}

void CGameServer::procTimeoutCache(const std::uint32_t seq, const std::uint64_t proctime)
{
	std::map<std::uint32_t, stCacheLoginInfo>::const_iterator itor = m_cacheAccountInfo.find(seq);
	if (m_cacheAccountInfo.end() == itor)
	{
		log_error("find no cacheseq,%u", seq);
		return;
	}

	if (0 == itor->second.agentSrvId)
	{
		log_error("unexcept agent srv id");
	}

	if (0 == itor->second.uid)
	{
		log_error("wrong uid,%u", itor->second.uid);
	}

	account_proto::VerifyLoginTokenResp rsp;
	rsp.set_temp_uin(itor->second.tempUin);
	rsp.set_uid(itor->second.uid);
	rsp.set_agency(itor->second.agency);
	rsp.set_agency_id(itor->second.agencyId);
	rsp.set_username(itor->second.username);
	rsp.set_token(itor->second.token);
	rsp.set_balance(itor->second.balance);
	rsp.set_game(itor->second.game);
	rsp.set_hall_url(itor->second.hallUrl);
	rsp.set_platform(itor->second.platform);
	rsp.set_gameinfo(itor->second.ext);
	rsp.set_currency(itor->second.currency);
	rsp.set_currency_unit_multi(itor->second.currency_unit_multi);
	rsp.set_currency_label(itor->second.currency_label);
	if (!itor->second.trans.empty())
	{
		rsp.set_trans(itor->second.trans);
	}

	if (itor->second.agentSrvId > 0)
	{
		log_debug("resp:%s", rsp.ShortDebugString().c_str());
		m_pHost->SendToPlayerViaAgent(account_proto::ACCOUNT_CMD_VERIFY_LOGIN_TOKEN_RESP, &rsp, itor->second.uid, itor->second.agentSrvId);
	}
	log_debug("login cache time out proc,uid,%u", itor->second.uid);
	m_cacheAccountInfo.erase(itor);

	return;
}
std::uint32_t CGameServer::genSeq(void)
{
	static std::uint32_t s_utransseq = 0;
	while (!(s_utransseq = ++s_utransseq % std::numeric_limits<unsigned int>::max()))
	{
	}

	return s_utransseq;
}







